/*
 * Copyright 2008 Neil Bacon
 * Distributed under the terms of the Mozilla Public License version 1.1
 * or the GNU General Public License version 3.
 */

package nb.xadd.node.util;

import java.util.BitSet;

import nb.xadd.node.Node;
import nb.xadd.node.impl.AbstractDecisionNode;
import nb.xadd.node.impl.BooleanDecisionNode;
import nb.xadd.node.impl.RealEqualDecisionNode;
import nb.xadd.node.impl.RealGreaterOrEqualDecisionNode;

public class NodeUtils {

    /** Only static methods. */
    private NodeUtils() {
    }

    /**
     * Apply visitor to every node in the tree rooted at n.
     * @param n
     * @param visitor
     */
    public static void walk(Node n, Visitor visitor) {
        visitor.visit(n);
        if (n instanceof AbstractDecisionNode) {
            AbstractDecisionNode dn = (AbstractDecisionNode) n;
            walk(dn.getTrueChild(), visitor);
            walk(dn.getFalseChild(), visitor);
        }
    }

    /**
     * Set a bit in one of the BitSets for each variable referenced in a DecisionNode
     * in the tree rooted at n.
     * Call with clear BitSets for node types of interest (or null if not interested).
     * Non-null BitSets are populated on return.
     * @param n tree to search
     * @param booleanVars variables referenced in BooleanDecisionNodes (may be null if not interested)
     * @param realEqualVars variables referenced in RealEqualDecisionNodes (may be null if not interested)
     * @param realGreaterOrEqualVars variables referenced in RealGreaterOrEqualDecisionNodes (may be null if not interested)
     */
    public static void getVariables(Node n, final BitSet booleanVars, final BitSet realEqualVars, final BitSet realGreaterOrEqualVars) {
        Visitor visitor = new Visitor() {
            @Override
            public void visit(Node n) {
                if (realGreaterOrEqualVars != null && n instanceof RealGreaterOrEqualDecisionNode) {
                    realGreaterOrEqualVars.set(((RealGreaterOrEqualDecisionNode) n).getRealVarIndex());
                } else if (realEqualVars != null && n instanceof RealEqualDecisionNode) {
                    realEqualVars.set(((RealEqualDecisionNode) n).getRealVarIndex());
                } else if (booleanVars != null && n instanceof BooleanDecisionNode) {
                    booleanVars.set(((BooleanDecisionNode) n).getBooleanVarIndex());
                }
            }
        };
        walk(n, visitor);
    }


    // Nested classes...

    public interface Visitor {
        void visit(Node n);
    }

}
